package com.mini.grpc.spring.server;

import com.mini.grpc.server.BindableService;
import com.mini.grpc.server.ServerInterceptor;
import com.mini.grpc.server.ServerServiceDefinition;
import com.mini.grpc.spring.annotation.GrpcService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

/**
 * gRPC服务注册表
 * 负责发现、注册和管理所有gRPC服务
 * 
 * @author Mini-gRPC
 */
@Component
public class GrpcServiceRegistry implements BeanPostProcessor, ApplicationContextAware {
    
    private static final Logger logger = Logger.getLogger(GrpcServiceRegistry.class.getName());
    
    private ApplicationContext applicationContext;
    private final Map<String, GrpcServiceInfo> services = new ConcurrentHashMap<>();
    private final List<GrpcServiceInfo> orderedServices = new ArrayList<>();
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanClass = bean.getClass();
        GrpcService grpcService = AnnotationUtils.findAnnotation(beanClass, GrpcService.class);
        
        if (grpcService != null && grpcService.enabled()) {
            if (bean instanceof BindableService) {
                registerService(bean, beanName, grpcService);
            } else {
                logger.warning("Bean " + beanName + " is annotated with @GrpcService but does not implement BindableService");
            }
        }
        
        return bean;
    }
    
    /**
     * 注册gRPC服务
     * 
     * @param serviceBean 服务Bean
     * @param beanName Bean名称
     * @param grpcService 注解信息
     */
    private void registerService(Object serviceBean, String beanName, GrpcService grpcService) {
        try {
            BindableService bindableService = (BindableService) serviceBean;
            ServerServiceDefinition serviceDefinition = bindableService.bindService();
            
            // 创建服务信息
            GrpcServiceInfo serviceInfo = new GrpcServiceInfo(
                    beanName,
                    serviceBean,
                    serviceDefinition,
                    grpcService,
                    resolveInterceptors(grpcService.interceptors())
            );
            
            String serviceName = serviceDefinition.getServiceDescriptor().getName();
            services.put(serviceName, serviceInfo);
            
            // 按优先级排序
            orderedServices.add(serviceInfo);
            orderedServices.sort(Comparator.comparingInt(s -> s.getAnnotation().priority()));
            
            logger.info("Registered gRPC service: " + serviceName + " (bean: " + beanName + ")");
            
        } catch (Exception e) {
            logger.severe("Failed to register gRPC service " + beanName + ": " + e.getMessage());
            throw new RuntimeException("Failed to register gRPC service " + beanName, e);
        }
    }
    
    /**
     * 解析拦截器
     * 
     * @param interceptorClasses 拦截器类数组
     * @return 拦截器列表
     */
    private List<ServerInterceptor> resolveInterceptors(Class<?>[] interceptorClasses) {
        List<ServerInterceptor> interceptors = new ArrayList<>();
        
        for (Class<?> interceptorClass : interceptorClasses) {
            try {
                Object interceptorBean = applicationContext.getBean(interceptorClass);
                if (interceptorBean instanceof ServerInterceptor) {
                    interceptors.add((ServerInterceptor) interceptorBean);
                } else {
                    logger.warning("Interceptor class " + interceptorClass.getName() + 
                                 " does not implement ServerInterceptor");
                }
            } catch (Exception e) {
                logger.warning("Failed to resolve interceptor " + interceptorClass.getName() + ": " + e.getMessage());
            }
        }
        
        return interceptors;
    }
    
    /**
     * 获取所有注册的服务
     * 
     * @return 服务信息列表
     */
    public List<GrpcServiceInfo> getAllServices() {
        return new ArrayList<>(orderedServices);
    }
    
    /**
     * 根据服务名获取服务信息
     * 
     * @param serviceName 服务名
     * @return 服务信息
     */
    public GrpcServiceInfo getService(String serviceName) {
        return services.get(serviceName);
    }
    
    /**
     * 获取服务数量
     * 
     * @return 服务数量
     */
    public int getServiceCount() {
        return services.size();
    }
    
    /**
     * 检查是否包含指定服务
     * 
     * @param serviceName 服务名
     * @return 是否包含
     */
    public boolean containsService(String serviceName) {
        return services.containsKey(serviceName);
    }
    
    /**
     * gRPC服务信息
     */
    public static class GrpcServiceInfo {
        private final String beanName;
        private final Object serviceBean;
        private final ServerServiceDefinition serviceDefinition;
        private final GrpcService annotation;
        private final List<ServerInterceptor> interceptors;
        
        public GrpcServiceInfo(String beanName, 
                             Object serviceBean,
                             ServerServiceDefinition serviceDefinition,
                             GrpcService annotation,
                             List<ServerInterceptor> interceptors) {
            this.beanName = beanName;
            this.serviceBean = serviceBean;
            this.serviceDefinition = serviceDefinition;
            this.annotation = annotation;
            this.interceptors = Collections.unmodifiableList(new ArrayList<>(interceptors));
        }
        
        public String getBeanName() {
            return beanName;
        }
        
        public Object getServiceBean() {
            return serviceBean;
        }
        
        public ServerServiceDefinition getServiceDefinition() {
            return serviceDefinition;
        }
        
        public GrpcService getAnnotation() {
            return annotation;
        }
        
        public List<ServerInterceptor> getInterceptors() {
            return interceptors;
        }
        
        public String getServiceName() {
            return serviceDefinition.getServiceDescriptor().getName();
        }
        
        @Override
        public String toString() {
            return "GrpcServiceInfo{" +
                    "beanName='" + beanName + '\'' +
                    ", serviceName='" + getServiceName() + '\'' +
                    ", priority=" + annotation.priority() +
                    ", interceptors=" + interceptors.size() +
                    '}';
        }
    }
} 